#ifndef SOL_HPP_
#   define SOL_HPP_

#   include "VRPTW.hpp"
#   include <cassert>
#   define  IT_END_VALUE    ((unsigned char)0xFE)

struct ServiceInfo
{	
	unsigned char	siClient;			// numero du client
	
	
	
	double		siArrivalDate;		// date d'arrivee chez le client
	double		siDepartureDate;	// date ou le vehicule est pret a partir
	double		siWaitTime;			// temps d'attente d'ouverture du client
	double		siStayTime;			// temps total passé chez le client
	
	double 		siAcceptableLocalDelay;	// temps correspondant au retard admissible
										// par rapport au clients suivants (par exemple D -> 1 -> 3 -> 5 -> D)
										// avec 	ciAdmissibleRetardTime(5) = 0
										// alors 	ciAdmissibleRetardTime(3) = ciAdmissibleRetardTime(5) + ciWaitTime(3)
										// et		ciAdmissibleRetardTime(1) = ciAdmissibleRetardTime(3) + ciWaitTime(1)
										// On peut inserer un client x avant 1 si ciAdmissibleRetardTime(1) >= TEMPS(D -> x -> 1)
		
		
	double 		siAcceptableGlobalDelay;
		// si ciWaitTime(k) == 0
		//	alors ciAdmissibleRetardTime(k) = (ciArrivalDate(k) - clDueDate)
		// sinon
		//  alors ciAdmissibleRetardTime(k) = ciAdmissibleRetardTime(k - 1) + ciWaitTime(k)
		// ciAdmissibleRetardTime(k) = ((ciArrivalDate(k) - clDueDate) < C) ? 0 : ciAdmissibleRetardTime(k - 1) + ciWaitTime(k);
		// avec C = 0.02 par exemple
		
	int			siCCapacityAtArrival;		// capacite cumulee a l'arrivee
	int			siCCapacityAtDeparture;		// capacite cumulee au depart
	
	double		siCDistanceAtArrival;	// distance cumulee a l'arrivee
	double		siCDistanceAtDeparture;	// distance cumulee au depart (pour depot uniquement)	
	
	
	double		siCTimeAtArrival;	// temps cumule a la date d'arrivee chez le client
	double		siCTimeAtReady;		// temps cumule a la date où le vehicule est pret a partir
};


class Vehicle
{
    public:
        Vehicle()
            : veVRPTW(0)
        {
            veId = 0xFFFFFFFF;
        }
    
        Vehicle(VRPTW*  inVRPTW, unsigned inId)
            :   veVRPTW(inVRPTW),
                veItBDepot(Iterator(this, inVRPTW->size())),
                veItEDepot(Iterator(this, inVRPTW->size() + 1)),
                veItEnd(Iterator(this, IT_END_VALUE)),
                veId(inId)
        {
			assert(inVRPTW != 0);
		}
        
        void    reset(VRPTW* inVRPTW, unsigned inId)
        {
            assert(inVRPTW != 0);
            veVRPTW = inVRPTW;
            veId = inId;
            veItBDepot = Iterator(this, inVRPTW->size());
            veItEDepot = Iterator(this, inVRPTW->size() + 1);
            veItEnd = Iterator(this, IT_END_VALUE);
            veItBDepot.veitVehicle = this;
            veItBDepot.veitValue = inVRPTW->size();
            veItEDepot.veitVehicle = this;
            veItEDepot.veitValue = inVRPTW->size() + 1;
            veItEnd.veitVehicle = this;
            veItEnd.veitValue = IT_END_VALUE;
        }
        
        void    erase(unsigned char inClient);
        void    update(unsigned char inClient);
        bool    update2(unsigned char inClient);
        
    class Iterator
    {
        public:
            Iterator()
            {
                veitVehicle = 0;
                veitValue = IT_END_VALUE;
            }
        
            Iterator(Vehicle* inVehicle, unsigned char inValue)
                : veitVehicle(inVehicle), veitValue(inValue)
            {}
           
        public:
			Iterator(const Iterator& inIt)
			{
				veitVehicle = inIt.veitVehicle;
				veitValue = inIt.veitValue;		// ?
			}
        
            ~Iterator()
            {}
        
            Vehicle*        veitVehicle;
            unsigned char   veitValue;
            
            Iterator&		operator=(const Iterator& inIt)
            {
				if (&inIt == this)
					return (*this);
					
				veitVehicle = inIt.veitVehicle;
				veitValue = inIt.veitValue;
				return (*this);
			}
            
            Iterator&		operator=(unsigned char inClient)
            {
				veitValue = inClient;
				return (*this);
			}
            
            Iterator&       operator++()
            {
                assert(veitVehicle != 0);
                if (veitValue == IT_END_VALUE)
                    return (*this);
                veitValue = veitVehicle->veSuccs[veitValue];
                return (*this);
            }
            
            Iterator&       operator--()
            {
                assert(veitVehicle != 0);
                if (veitValue == IT_END_VALUE)
                    return (*this);
                veitValue = veitVehicle->vePreds[veitValue];
                return (*this);
            }
            
            operator unsigned char()
            {
				return (veitValue);
			}
            
            ServiceInfo&    info()
            {
                assert(veitValue != IT_END_VALUE);
                return (veitVehicle->veInfos[veitValue]);
            }
            
            const ServiceInfo&    info() const
            {
                assert(veitValue != IT_END_VALUE);
                return (veitVehicle->veInfos[veitValue]);
            }
            
            friend  bool    operator==(const Iterator& in1, const Iterator& in2);
            friend  bool    operator!=(const Iterator& in1, const Iterator& in2);
    };
    
    const Iterator&             bdepot() const
    {
        return (veItBDepot);
    }
    
    const Iterator&             edepot() const
    {
        return (veItEDepot);
    }
    
    const Iterator&            end() const
    {
        return (veItEnd);
    }
    
    Iterator					iterator() const
    {	return (Iterator(veItBDepot));	}
    
    void				 insert(unsigned char inClient, 
								unsigned char inA,
								unsigned char inB);

    bool				 insert2(	unsigned char inClient, 
									unsigned char inA,
									unsigned char inB);

	bool				 contains(unsigned char inClient) const
	{
		if (inClient == veVRPTW->size() || inClient == (veVRPTW->size() + 1))
			return (true);
			
		return (veTourneeByClient[inClient] == veId);
	}
	
	std::string			 toString() const;
    
    VRPTW*               veVRPTW;
    Iterator             veItBDepot;    // begin depot
    Iterator             veItEDepot;    // end depot
    Iterator             veItEnd;       // end, iterator with value 0xFE
    
    unsigned char        veId;
    unsigned char*       veSuccs;
    unsigned char*       vePreds;
    ServiceInfo*         veInfos;
    unsigned char*       veTourneeByClient;
    unsigned char*       veSize;
    
    unsigned char&       getrSize()
    {   return (*veSize);   }
    
};



class Sol
{
    public:
        struct Eval
        {
            double      seDistance;
            unsigned    seVehicles;
            bool        seComplete;
            
            std::string toString()  const
            {
                char    buffer[0x1000];
                
                sprintf(buffer, "[ %s ; (%u ; %2.2f) ]", 
                                    seComplete ? "COMPLETE" : "INCOMPLETE",
                                    seVehicles,
                                    seDistance
                                );
                
                return (buffer);
            }
            
            friend 		bool 		operator<(const Sol::Eval& in1, const Sol::Eval& in2);
        };
    
        Sol(VRPTW&  inVRPTW);
        Sol(const Sol& inSol);
        ~Sol();
        
        Sol&    operator=(const Sol& inSol);
        
        const Vehicle&	 operator[](unsigned inIndex)
        {
            assert(inIndex < soVRPTW.size());
            return (soVehicles[inIndex]);
        }
        
        Vehicle&         getrVehicle(unsigned inIndex)
        {
            assert(inIndex < soVRPTW.size());
            return (soVehicles[inIndex]);
        }
        
        std::string		toString() const;
        
        void            eval(Sol::Eval& inSolEval) const;
        
        const unsigned char*	getTourneeByClient() const
        {	return (soTourneeByClient);	}
        
        void			clear();
        
    protected:
        VRPTW&                      soVRPTW;
        unsigned char*              soPreds;
        unsigned char*              soSuccs;
        unsigned char*              soTourneeByClient;
        unsigned char*              soSizeByTournee;
        ServiceInfo*                soInfos;
        
        Vehicle*                    soVehicles;
};

#endif
